#include "CTerrain_sm5.h"


	CTerrain_sm5::CTerrain_sm5()
	{
		Create();
	}


	CTerrain_sm5::~CTerrain_sm5()
	{
	}


	void CTerrain_sm5::Release()
	{
		delete this;
	}


	bool CTerrain_sm5::Create()
	{
		uvec2	v_dim( 8 );


		// init virtual texture manager
		typedef CVirtualTextureManager::TDescriptor::TTexture	TTexture;

		CVirtualTextureManager::TDescriptor	s_desc;

		s_desc.aTexInfo.PushBack( TTexture( e_rt_format::RGBA8, e_tex_swizzle::AUTO,
											e_tex_flags::CLAMP_TO_EDGE | e_tex_flags::BILINEAR ) );
		s_desc.aTexInfo.PushBack( TTexture( e_rt_format::RGBA8, e_tex_swizzle::AUTO,
											e_tex_flags::CLAMP_TO_EDGE | e_tex_flags::BILINEAR ) );
		s_desc.uBlockDim	= 256;
		s_desc.vDimension	= uvec2( 2048, 2048 );

		CHECK_RETURN( _cVTex.Create( s_desc ) );


		// init landscape min LOD
		CHECK_RETURN( RESMAN()->Create( e_resource::TEXTURE_2D, _pHeightNormal, nullptr, false ) );
		CHECK_RETURN( RESMAN()->Create( e_resource::TEXTURE_2D, _pVTexCoord, nullptr, false ) );

		CHECK_RETURN( _pHeightNormal->CreateRT( uvec3(v_dim, 0), e_rt_format::RGBA8, e_tex_swizzle::AUTO,
												e_tex_flags::CLAMP_TO_EDGE | e_tex_flags::BILINEAR ) );
		CHECK_RETURN( _pVTexCoord->CreateRT( uvec3(v_dim, 0), e_rt_format::RGBA_16UI, e_tex_swizzle::AUTO,
											 e_tex_flags::CLAMP_TO_EDGE | e_tex_flags::BILINEAR ) );


		// create grid
		TMultiMesh	s_mesh;

		CHECK_RETURN( Geometry::GenerateGrid( s_mesh, GetPOT( v_dim.Max() ), 4, gl_vertex::FLOAT, gl_index::UINT_32 ) );
		//CHECK_RETURN( Geometry::CreateGrid( s_mesh, 128, 1.f, 3 ) );

		CHECK_RETURN( RESMAN()->Create( e_resource::MESH, _pGrid, nullptr, false ) );
		CHECK_RETURN( _pGrid->Create( s_mesh, e_mesh_flags::STATIC ) );


		// load shaders
		CHECK_RETURN( RESMAN()->Load( e_resource::SHADER_PROGRAM, _pLod0, "terrain/vterrain_sm5_lod0.prg", e_prog_flags::LINK ) );
		CHECK_RETURN( RESMAN()->Load( e_resource::SHADER_PROGRAM, _pLod0_v1, "terrain/vterrain_sm4_lod0.prg", e_prog_flags::LINK ) );

		_pLod0->Bind();
		glUniform1i( _pLod0->GetUniform("unHeightNormalMap"), 0 );
		glUniform1i( _pLod0->GetUniform("unTexPosMap"), 1 );
		_pLod0->Unbind();

		_sTerrainData.vSize			= v_dim.To<vec2>();
		_sTerrainData.fGridScale	= 0.5f;
		_sTerrainData.fHeightScale	= 1.f;

		return true;
	}
	
	
	void CTerrain_sm5::_s_Draw(void *pThis, void *pParam)
	{
		((CTerrain_sm5 *)pThis)->DrawLod0();
	}

	
	void CTerrain_sm5::DrawLod0()
	{
		//SMAN()->PolygonMode( gl_polygon_mode::LINE );

		_pLod0->Bind();
		
		uint	idx  = _pLod0->GetUniformBlockIndex( "inTerrainParams" );
		usize	size = _pLod0->GetUniformBlockSize( idx );
		ASSERT( size == sizeof(_sTerrainData) );
		RENDER()->GetUBOManager()->SetData( _pLod0->GetIdent(), 0, idx, &_sTerrainData, sizeof(_sTerrainData) );
		
		MSTACK()->PushMatricesMVP();
		MSTACK()->SetMatrix( mat4::BuildOrtho2D( frect( -1.f, -1.f, 1.f, 1.f ) ), e_transform::PROJECTION );
		MSTACK()->SetMatrix( mat4::Identity(), e_transform::VIEW );
		MSTACK()->SetMatrix( mat4::Translate( vec3( 0, 0, -0.5f ) ), e_transform::MODEL );

		glUniformMatrix4fv( _pLod0->GetUniform("unTransform.MVP"), 1, GL_FALSE, MSTACK()->GetMatrixMVP().ptr() );
		MSTACK()->PopMatricesMVP();

		RENDERGL()->EnableTessellation( true, 4 );

		_pHeightNormal->Bind(0);
		_pVTexCoord->Bind(1);
		_pGrid->Draw();

		_pLod0->Unbind();

		RENDERGL()->EnableTessellation( false );
		//SMAN()->PolygonMode( gl_polygon_mode::FILL );
	}
	

	void CTerrain_sm5::DrawLod0v1()
	{
		_pLod0_v1->Bind();

		MSTACK()->SetMatrix( mat4::BuildOrtho2D( frect( -1.f, -1.f, 1.f, 1.f ) ), e_transform::PROJECTION );
		MSTACK()->SetMatrix( mat4::Identity(), e_transform::VIEW );
		MSTACK()->SetMatrix( mat4::Translate( vec3( 0.f, 0.f, -0.5f ) ), e_transform::MODEL );

		glUniformMatrix4fv( _pLod0_v1->GetUniform("unTransform.MVP"), 1, GL_FALSE, MSTACK()->GetMatrixMVP().ptr() );

		_pHeightNormal->Bind(0);
		_pVTexCoord->Bind(1);
		_pGrid->Draw();

		_pLod0_v1->Unbind();
	}


	void CTerrain_sm5::Destroy()
	{
	}


	void CTerrain_sm5::Update()
	{
	}


	void CTerrain_sm5::Render(TCameraRenderQueue *pCRQ, const mat4 &sModelMat)
	{
		TRenderObject	s_ro;

		s_ro.SetRenderOp( &_s_Draw, this, nullptr );
		s_ro.sModelMatrix = sModelMat;
	
		pCRQ->PushRenderObj( e_render_layer::OPAQUE_0, s_ro );
	}


	void CTerrain_sm5::GetEditor(ITerrainEditor *&pEditor)
	{
		pEditor = this;
	}


	void CTerrain_sm5::EnableEditing(uint uLayer)
	{
	}


	void CTerrain_sm5::DisableEditing()
	{
		// update normals
	}
	
	
	int CTerrain_sm5::GetCurrentLayer()
	{
		return -1;
	}
	
	
	void CTerrain_sm5::DotBrush(const vec3 &vWPos, float fPower)
	{
	}
	
	
	void CTerrain_sm5::RoundBrush(const vec3 &vWPos, float fRadius, float fPower)
	{
	}
	
	
	void CTerrain_sm5::Brush(const TBrush &sBrush, const vec3 &vWPos, float fSize, float fPower)
	{
	}
	
	/*
	bool CTerrain_sm5::RoundBrush(const vec3 &vWPos, float fRadius, float fPower)
	{
		aabb_f	s_box;
		vec3	v_extent( vec2( _uGridSize * _sTerrainData.fGridScale ), _sTerrainData.fHeightScale );

		s_box.SetBBox( vec3( _vGridCenter, 0.f ), v_extent );

		if ( !s_box.IsInside( vWPos ) )
			return true;
		
		vec2	v_pos	= (vWPos.xy() - _vGridCenter) / (_sTerrainData.fGridScale * _uGridSize) + 0.5f;
		FBO_t	*p_fbo	= RENDER()->GetPPManager()->GetFrameBuffer();
		

		// pass1 //
		p_fbo->AttachTexture( _pReserveHN, e_fbo_attach::COLOR_0 );
		p_fbo->SetSize( _pReserveHN->GetDimension() );
		p_fbo->Bind();

		_pHeightNormal->Bind(0);
		_pUpdateHeight->Bind();
		glUniform4f( _pUpdateHeight->GetUniform("unBrushData"), v_pos.x, v_pos.y, fRadius, fPower );
		
		RENDERGL()->DrawFSQuad();

		SMAN()->UnbindTexture(0);
		p_fbo->Unbind();


		// pass2 //
		p_fbo->AttachTexture( _pHeightNormal, e_fbo_attach::COLOR_0 );
		p_fbo->SetSize( _pHeightNormal->GetDimension() );
		p_fbo->Bind( s_area );

		_pReserveHN->Bind(0);

		_pUpdateNormal->Bind();
		RENDERGL()->DrawFSQuad();

		SMAN()->UnbindTexture( 0 );
		p_fbo->Unbind();


		p_fbo->Detach( e_fbo_attach::COLOR_0 );
		RENDER()->GetPPManager()->FreeFrameBuffer( p_fbo );
		
		return true;
	}


	bool CTerrain_sm5::VTexRoundBrush(const vec3 &vWPos, float fRadius, float fPower)
	{
		aabb_f	s_box;
		vec3	v_extent( vec2( _uGridSize * _sTerrainData.fGridScale ), _sTerrainData.fHeightScale );

		s_box.SetBBox( vec3( _vGridCenter, 0.f ), v_extent );

		if ( !s_box.IsInside( vWPos ) )
			return true;

		ivec2	v_pos	= ( (vWPos.xy() - _vGridCenter) / _sTerrainData.fGridScale ).To<ivec2>() + (_uGridSize >> 1);
		index_t	s_index	= _aTexCoords[ v_pos.x + v_pos.y * _uGridSize ];
		recti	s_area	= _cVTex.GetCoords( s_index ).To<recti>();
		vec2	v_vtpos	= ;
		FBO_t	*p_fbo	= RENDER()->GetPPManager()->GetFrameBuffer();


		// pass1 //
		p_fbo->AttachTexture( _cVTex.GetTextures()[0].pReserve, e_fbo_attach::COLOR_0 );
		p_fbo->SetSize( s_area.GetSize().To<uvec2>() );
		p_fbo->Bind();

		_cVTex.GetTextures()[0].pMain->Bind(0);
		_pUpdateHeight->Bind();
		glUniform4f( _pUpdateHeight->GetUniform("unBrushData"), v_vtpos.x, v_vtpos.y, fRadius, fPower );
		
		RENDERGL()->DrawFSQuad();

		SMAN()->UnbindTexture(0);
		p_fbo->Unbind();


		// pass2 //
		p_fbo->AttachTexture( _cVTex.GetTextures()[0].pMain, e_fbo_attach::COLOR_0 );
		p_fbo->SetSize( _cVTex.GetDimension() );
		p_fbo->Bind( s_area );

		_cVTex.GetTextures()[0].pReserve->Bind(0);

		_pUpdateNormal->Bind();
		RENDERGL()->DrawFSQuad();

		SMAN()->UnbindTexture( 0 );
		p_fbo->Unbind();


		p_fbo->Detach( e_fbo_attach::COLOR_0 );
		RENDER()->GetPPManager()->FreeFrameBuffer( p_fbo );

		return true;
	}
	*/